package cn.mdmbct.spring.starter.douyin.common.config;

import cn.mdmbct.douyin.common.config.AppConfig;
import cn.mdmbct.douyin.common.config.DyOpenApiConfig;
import cn.mdmbct.douyin.common.config.HttpConfig;
import cn.mdmbct.douyin.common.enums.StorageType;
import cn.mdmbct.douyin.common.redis.DyRedisOps;
import cn.mdmbct.douyin.common.redis.JedisOps;
import cn.mdmbct.douyin.common.redis.RedisTemplateOps;
import cn.mdmbct.douyin.common.storage.DyStorageManager;
import cn.mdmbct.douyin.common.storage.MemoryStorageManager;
import cn.mdmbct.douyin.common.storage.RedisStorageManager;
import cn.mdmbct.spring.starter.douyin.common.validator.DyOpenAppValidator;
import cn.mdmbct.spring.starter.douyin.common.properties.dy.DyOpenApiProperties;
import cn.mdmbct.spring.starter.douyin.common.properties.storage.JedisProperties;
import cn.mdmbct.spring.starter.douyin.common.properties.storage.StorageProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 数据存储配置
 *
 * @author mdmbct  mdmbct@outlook.com
 * @date 2021/3/9 13:37
 * @modified mdmbct
 * @since 1.0
 */
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties({DyOpenApiProperties.class, StorageProperties.class})
public class DyOpenApiStorageAutoConfiguration extends CachingConfigurerSupport {

    private final ApplicationContext applicationContext;

    @Bean
    @ConditionalOnMissingBean
    public DyStorageManager dyConfigStorage(DyOpenApiProperties apiProperties, StorageProperties storageProperties) {

        StorageType storageType = storageProperties.getType();
        DyStorageManager dyStorageManager;
        // 检查open api配置是否有效
        DyOpenAppValidator.isValid(apiProperties.getApp());

        DyOpenApiConfig config = apiPropertiesToApiConfig(apiProperties);

        switch (storageType) {
            case MEMORY:
                dyStorageManager = getMemoryConfigStorageManager(config, storageProperties.getMemoryLocalSave());
                break;
            case REDIS_TEMPLATE:
                dyStorageManager = getRedisConfigStorageManager(config);
                break;
            case JEDIS:
                dyStorageManager = getJedisConfigStorageManager(config, storageProperties);
                break;
            default:
                dyStorageManager = getDefaultStorageManager(config);
                break;
        }
        return dyStorageManager;
    }
    
    private DyOpenApiConfig apiPropertiesToApiConfig(DyOpenApiProperties apiProperties) {
        DyOpenApiConfig config = new DyOpenApiConfig();
        config.setConfigCacheKey(apiProperties.getConfigCacheKey());

        AppConfig appConfig = new AppConfig();
        BeanUtils.copyProperties(apiProperties.getApp(), appConfig);
        config.setApp(appConfig);

        HttpConfig httpConfig = new HttpConfig();
        BeanUtils.copyProperties(apiProperties.getHttp(), httpConfig);
        config.setHttp(httpConfig);
        return config;
    }

    private DyStorageManager getJedisConfigStorageManager(DyOpenApiConfig config, StorageProperties storageProperties) {

        JedisPool jedisPool;
        if (storageProperties.getJedis() == null || storageProperties.getJedis().getHost() == null || storageProperties.getJedis().getPort() == 0) {
            jedisPool = applicationContext.getBean(JedisPool.class);
        } else {
            jedisPool = getJedisPool(storageProperties.getJedis());
        }
        DyRedisOps jedisOps = new JedisOps(jedisPool);
        return new RedisStorageManager(jedisOps, config);
    }

    private JedisPool getJedisPool(JedisProperties jedisConfigProperties) {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        if (jedisConfigProperties.getMaxTotal() != null) {
            jedisPoolConfig.setMaxTotal(jedisConfigProperties.getMaxTotal());
        }
        if (jedisConfigProperties.getMaxIdle() != null) {
            jedisPoolConfig.setMaxIdle(jedisConfigProperties.getMaxIdle());
        }
        if (jedisConfigProperties.getMaxWaitMillis() != null) {
            jedisPoolConfig.setMaxWaitMillis(jedisConfigProperties.getMaxWaitMillis());
        }
        if (jedisConfigProperties.getMinIdle() != null) {
            jedisPoolConfig.setMinIdle(jedisConfigProperties.getMinIdle());
        }
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPoolConfig.setTestOnReturn(true);
        return new JedisPool(jedisPoolConfig,
                jedisConfigProperties.getHost(),
                jedisConfigProperties.getPort(),
                jedisConfigProperties.getTimeout(),
                jedisConfigProperties.getPassword(),
                jedisConfigProperties.getDatabase());
    }


    private DyStorageManager getMemoryConfigStorageManager(DyOpenApiConfig config, String memoryLocalSave) {
        return new MemoryStorageManager(config, memoryLocalSave);
    }

    private DyStorageManager getRedisConfigStorageManager(DyOpenApiConfig config) {

        StringRedisTemplate redisTemplate = null;
        try {
            redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (null == redisTemplate) {
                redisTemplate = (StringRedisTemplate) applicationContext.getBean("stringRedisTemplate");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (null == redisTemplate) {
            redisTemplate = (StringRedisTemplate) applicationContext.getBean("redisTemplate");
        }

        DyRedisOps redisOps = new RedisTemplateOps(redisTemplate);
        return new RedisStorageManager(redisOps, config);

    }

    /**
     * 默认配置存储管理器使用redis
     *
     * @param config open api 配置
     */
    private DyStorageManager getDefaultStorageManager(DyOpenApiConfig config) {
        return getRedisConfigStorageManager(config);
    }


}
